Skip to content

Conversation

@shashankshampi
Copy link

@shashankshampi shashankshampi commented Sep 26, 2024

Test Plan: https://www.notion.so/Gossipsub-651e02d4d7894bb2ac1e4edb55f3192d

Topic Membership Tests:

Test added: (TC6.6: Verify the handling of subscription changes when the underlying pubsub framework sends SUBSCRIBE and UNSUBSCRIBE events.)

  1. Simulate the SUBSCRIBE event and check proper handling in the mesh and gossipsub structures
  2. This test will simulate an UNSUBSCRIBE event and check if the topic is removed from the relevant data structures but remains in gossipsub
  3. This test ensures that multiple topics can be subscribed to and unsubscribed from, with proper initialization of the topic structures.
  4. This test ensures that the number of subscriptions does not exceed the limit set in the GossipSub parameters

Part 2:

TC6.1: Verify that peers can correctly join a topic using JOIN(topic).
TC6.2: Ensure that peers can correctly leave a topic using LEAVE(topic).
TC6.5: Multiple peers join and leave topic simultaneously

@shashankshampi shashankshampi marked this pull request as ready for review September 26, 2024 07:58
@diegomrsantos
Copy link
Contributor

how about testgossiptopicmembership.nim?

@diegomrsantos
Copy link
Contributor

We follow conventional commits for the PR title. In this case, it will start with test(gossipsub):

@shashankshampi
Copy link
Author

how about testgossiptopicmembership.nim?

I am adding other tests in the same file related to Topic Membership Tests for Join topic, leave topic, and mesh updated on peer subscribing and leaving topic.

Earlier suggestion looks fine but else will modify as per your suggestion

@shashankshampi
Copy link
Author

We follow conventional commits for the PR title. In this case, it will start with test(gossipsub):

Thanks. Will follow same in upcoming PRs

added test wrt subscribe and unsubscribe

added tests/pubsub/testgossipinternal2 file

linters

feat: rendezvous refactor (#1183)

Hello!

This PR aim to refactor rendezvous code so that it is easier to impl.
Waku rdv strategy. The hardcoded min and max TTL were out of range with
what we needed and specifying which peers to interact with is also
needed since Waku deals with peers on multiple separate shards.

I tried to keep the changes to a minimum, specifically I did not change
the name of any public procs which result in less than descriptive names
in some cases. I also wanted to return results instead of raising
exceptions but didn't. Would it be acceptable to do so?

Please advise on best practices, thank you.

---------

Co-authored-by: Ludovic Chenut <[email protected]>

refactor and suite name refactor

chore(ci): Enable S3 caching for interop (#1193)

- Adds our S3 bucket for caching docker images as Protocol Labs shut
down their shared one.
- Remove the free disk space workaround that prevented the jobs from
failing for using too much space for the images.

---------

Co-authored-by: diegomrsantos <[email protected]>

PR review comment changes
@shashankshampi shashankshampi changed the title Part 1: Test cases covering subscribe and unsubscribe Events test(gossipsub): Part 1 Test cases covering subscribe and unsubscribe Events Oct 1, 2024
@diegomrsantos
Copy link
Contributor

how about testgossiptopicmembership.nim?

I am adding other tests in the same file related to Topic Membership Tests for Join topic, leave topic, and mesh updated on peer subscribing and leaving topic.

Earlier suggestion looks fine but else will modify as per your suggestion

I'm not sure if gossip membership makes sense.

Copy link
Author

@shashankshampi shashankshampi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed review comment

Copy link
Author

@shashankshampi shashankshampi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All done

await gossipSub.switch.stop()

# Test for verifying peers joining a topic using `JOIN(topic)`
asyncTest "handle JOIN topic and mesh is updated":
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the difference between this case and the handle SUBSCRIBE to the topic one?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first test is primarily about verifying mesh behavior after joining.
The second test is broader and checks both mesh and gossipsub structures to ensure proper subscription handling.

In short, the second test provides a more thorough validation by checking both the mesh and gossipsub structures, while the first test is specifically focused on the mesh when peers join a topic.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you might be able to condense the two cases into one.

Are they two different cases in the test plans?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There were 6 TC on documentation, and I followed the same.
Let me know if this is not required now will remove it

Copy link
Author

@shashankshampi shashankshampi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed all the review comments as per request.

await gossipSub.switch.stop()

# Test for verifying peers joining a topic using `JOIN(topic)`
asyncTest "handle JOIN topic and mesh is updated":
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first test is primarily about verifying mesh behavior after joining.
The second test is broader and checks both mesh and gossipsub structures to ensure proper subscription handling.

In short, the second test provides a more thorough validation by checking both the mesh and gossipsub structures, while the first test is specifically focused on the mesh when peers join a topic.

@shashankshampi shashankshampi marked this pull request as ready for review October 24, 2024 13:47
Copy link
Collaborator

@strinnityk strinnityk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it'd be a good addition to this PR to also follow the Given-When-Then formula used in the rest of the codebase. It documents the case by high-level blocks, making it easier to understand for external eyes.

You can check other PRs and or test files for examples.
Also, here's an example using one of your implemented cases:

  asyncTest "handle SUBSCRIBE to the topic":
    # Given 5 gossipsub nodes
    let
      numberOfNodes = 5
      topic = "test-topic"
      nodes = generateNodes(numberOfNodes, gossip = true)

    await allFuturesThrowing(nodes.mapIt(it.switch.start()))

    # When all of them are connected and subscribed to the same topic
    await subscribeNodes(nodes)
    for node in nodes:
      node.subscribe(topic, voidTopicHandler)

    await sleepAsync(2 * DURATION_TIMEOUT)

    # Then their related attributes should reflect that
    for node in nodes:
      let currentGossip = GossipSub(node)

      check currentGossip.topics.contains(topic)
      check currentGossip.gossipsub[topic].len() == numberOfNodes - 1
      check currentGossip.mesh[topic].len() == numberOfNodes - 1

    await allFuturesThrowing(nodes.mapIt(allFutures(it.switch.stop())))

@shashankshampi
Copy link
Author

asyncTest "handle SUBSCRIBE to the topic":
    # Given 5 gossipsub nodes
    let
      numberOfNodes = 5
      topic = "test-topic"
      nodes = generateNodes(numberOfNodes, gossip = true)

    await allFuturesThrowing(nodes.mapIt(it.switch.start()))

    # When all of them are connected and subscribed to the same topic
    await subscribeNodes(nodes)
    for node in nodes:
      node.subscribe(topic, voidTopicHandler)

    await sleepAsync(2 * DURATION_TIMEOUT)

    # Then their related attributes should reflect that
    for node in nodes:
      let currentGossip = GossipSub(node)

      check currentGossip.topics.contains(topic)
      check currentGossip.gossipsub[topic].len() == numberOfNodes - 1
      check currentGossip.mesh[topic].len() == numberOfNodes - 1

    await allFuturesThrowing(nodes.mapIt(allFutures(it.switch.stop())))

Done. Added documentation as per Given When Then

@shashankshampi shashankshampi changed the title test(gossipsub): Part 1 Test cases covering subscribe and unsubscribe Events test(gossipsub): Topic Membership Tests Oct 25, 2024

await allFuturesThrowing(nodes.mapIt(it.switch.start()))

# When nodes subscribe and then unsubscribe to multiple topics
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd remove the second part here. Leave only: When nodes subscribe to multiple topics, as that's what you're doing here, and later you're handling the unsubscribe part.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment on lines 163 to 173
for topic in topicNames:
if gossipSub.topics.len < gossipSub.topicsHigh:
gossipSub.subscribe(
topic,
proc(topic: string, data: seq[byte]): Future[void] {.async.} =
discard
,
)
else:
# Then the subscription count should not exceed the limit
check gossipSub.topics.len == gossipSub.topicsHigh
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you don't need to handle the if gossipSub.topics.len < gossipSub.topicsHigh:. That's precisely the situation that we want to test, and that subscribe should be handling:

Suggested change
for topic in topicNames:
if gossipSub.topics.len < gossipSub.topicsHigh:
gossipSub.subscribe(
topic,
proc(topic: string, data: seq[byte]): Future[void] {.async.} =
discard
,
)
else:
# Then the subscription count should not exceed the limit
check gossipSub.topics.len == gossipSub.topicsHigh
for topic in topicNames:
gossipSub.subscribe(
topic,
proc(topic: string, data: seq[byte]): Future[void] {.async.} =
discard
,
)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

# Then the subscription count should not exceed the limit
check gossipSub.topics.len == gossipSub.topicsHigh

check gossipSub.topics.len == gossipSub.topicsHigh
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would check the gossipsub.topics.len against gossipSubParams, which is the limit you defined here. That would make the check accurate.

Also, maybe it'd be interesting to connect the nodes and check for mesh and gossipsub population.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


await allFuturesThrowing(nodes.mapIt(it.switch.start()))

# When nodes join and subscribe to the topic
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't join and subscribe the same thing?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed


await sleepAsync(2 * DURATION_TIMEOUT)

# When they all join the topic, their attributes should reflect this
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first half of this should be a bit up, because the connection and subscription is done in the lines above.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

check currentGossip.mesh.hasKey(topic)
check currentGossip.topics.contains(topic)

# When peers subscribe to each other's topics
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The subscription is done above, on the subscribe. This is just a synchronous check to turn the test deterministic: Make sure all nodes are connected between themselves.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Author

@shashankshampi shashankshampi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done all as per request


await allFuturesThrowing(nodes.mapIt(it.switch.start()))

# When nodes subscribe and then unsubscribe to multiple topics
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment on lines 163 to 173
for topic in topicNames:
if gossipSub.topics.len < gossipSub.topicsHigh:
gossipSub.subscribe(
topic,
proc(topic: string, data: seq[byte]): Future[void] {.async.} =
discard
,
)
else:
# Then the subscription count should not exceed the limit
check gossipSub.topics.len == gossipSub.topicsHigh
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

# Then the subscription count should not exceed the limit
check gossipSub.topics.len == gossipSub.topicsHigh

check gossipSub.topics.len == gossipSub.topicsHigh
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


await allFuturesThrowing(nodes.mapIt(it.switch.start()))

# When nodes join and subscribe to the topic
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed


await sleepAsync(2 * DURATION_TIMEOUT)

# When they all join the topic, their attributes should reflect this
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

check currentGossip.mesh.hasKey(topic)
check currentGossip.topics.contains(topic)

# When peers subscribe to each other's topics
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment on lines +197 to +198
check currentGossip.gossipsub.hasKey(topic)
check currentGossip.topics.contains(topic)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, do these checks as exhaustive as possible :)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all 3 validations is already there. Please help with any validation you think is missed out

Comment on lines +221 to +223
check currentGossip.gossipsub.hasKey(topic)
check currentGossip.mesh.hasKey(topic)
check currentGossip.topics.contains(topic)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here (re: exhaustiveness).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all three validations are already there. Please help with any validation you think is missed out

@rlve rlve closed this May 12, 2025
@github-project-automation github-project-automation bot moved this from backlog to done in nim-libp2p May 12, 2025
@richard-ramos richard-ramos deleted the block6Test branch August 28, 2025 14:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

8 participants